from datetime import date, timedelta
from django.conf import settings
from django.db.models import Manager
from django.contrib.auth.models import User
from django.contrib.sites.models import Site

class ActiveManager(Manager):
    """
    Adds an additional method to filter only active objects.
    """
    def active(self):
        return self.get_query_set().filter(active=True)

class AccountManager(Manager):

    def get_query_set(self):
        return super(AccountManager, self).get_query_set().extra(select={
            'days_active': """cast(
                                extract(day from age( 
                                	date_trunc('day', now()),
                                	date_trunc('day', accounts_account.created)
                                )) as integer)""",
            'total_revenue': """SELECT sum(accounts_payment.amount)
                                    FROM accounts_payment
                                        WHERE accounts_payment.success = True
                                            AND accounts_payment.account_id = accounts_account.id""",
            '_consecutive_declines': """SELECT count(*) FROM accounts_payment
                                            WHERE accounts_payment.account_id = accounts_account.id
                                            	AND success = False
                                            	AND accounts_payment.created > 
                                                    coalesce((SELECT created FROM accounts_payment
                                            			WHERE accounts_payment.account_id = accounts_account.id
                                            			AND success = True
                                            			ORDER BY created DESC
                                            			LIMIT 1), '01/01/1800'::date)"""})
    

    def active(self):
        from accounts.models import Account
        return self.get_query_set().filter(status=Account.ACTIVE)

    def disabled(self):
        from accounts.models import Account
        return self.get_query_set().filter(status=Account.DISABLED)

    def cancelled(self):
        from accounts.models import Account
        return self.get_query_set().filter(status=Account.CANCELLED)

    def by_signup_date(self, signup_date):
        return self.get_query_set().filter(
            created__day=signup_date.day,
            created__month=signup_date.month,
            created__year=signup_date.year,
        )

    def expiring_trials(self):
        """
        Returns all active Accounts on a paid rate plan that do not have a BillingProfile and
        have TRIAL_WARNING_PERIOD days left before reaching TRIAL_PERIOD.
        """
        from accounts.models import Account
        signup = date.today() - timedelta(days=settings.TRIAL_PERIOD - settings.TRIAL_WARNING_PERIOD)
        accounts = self.by_signup_date(signup).filter(status=Account.ACTIVE, billingprofile__isnull=True)
        id_list = [ a.id for a in accounts if a.calculate_monthly_charge() > 0 ]
        return accounts.filter(id__in=id_list).order_by('-created')
        
    def expired_trials(self):
        """
        Returns all Accounts on a paid rate plan that do not have a BillingProfile and
        whose account is past the TRIAL_PERIOD.
        """
        from accounts.models import Account
        signup = date.today() - timedelta(days=settings.TRIAL_PERIOD)
        accounts = self.by_signup_date(signup).filter(status=Account.ACTIVE, billingprofile__isnull=True)
        id_list = [ a.id for a in accounts if a.calculate_monthly_charge() > 0 ]
        return accounts.filter(id__in=id_list).order_by('-created')
    
    
    def get_current(self):
        """
        Returns the current Account, based on settings.SITE_ID.
        Fails silently and returns None if Acccount does not exist.
        Note: AttributeError will bubble up if settings.SITE_ID is not defined.
        """
        try:
            return self.get_query_set().get(site__id=settings.SITE_ID)
        except self.model.DoesNotExist:
            return None
            
    def create_new_account(self, **kwargs):
        """
        Creates a new Account using the data specified in `kwargs`.
        This handles all the behind the scenes work of creating an auth.User, Site, and AccountUser.
        
        Required keyword arguments:
            `name`: The Account name, used to create the Site. (ex: "Apple Corp.")
            `label`: A unique string for this account (letters and underscores only).
            `domain`: The base domain name.  `label` and `domain` are combined to create the full domain name, ie: <label>.<domain> (mylabel.example.com).
            `username`: The AccountUser's username (owner).
            `password`: Plain-text password for the AccountUser.
            `email`: The email address of the Account owner.
            `plan`: The RatePlan used to create the Account's Subscription.
        Optional keyword arguments:
            `first_name` and `last_name`: Used to create the underlying auth.User (defaults to empty string if not provided).
            `referrer`: the Account who referred this new account.
            `price_override`: Absolute price this account get billed per month.
        """
        from accounts.models import Account, AccountUser, new_referrer_code, new_account_number, new_user_number, ACCOUNT_USERNAME_DELIMITER
        account_number = new_account_number()
        user_number =new_user_number()
        account = Account(label=kwargs['label'])
        owner = User.objects.create(
            username="%s%s%s" % (account_number, ACCOUNT_USERNAME_DELIMITER, user_number),
            first_name=kwargs.get('first_name', ''),
            last_name=kwargs.get('last_name', ''),
            email=kwargs['email'],
        )
        owner.set_password(kwargs['password'])
        owner.save()
        account.auth_owner = owner
        site = Site.objects.create(
            name=kwargs['name'],
            domain = "%s.%s" % (kwargs['label'], kwargs['domain'])
        )
        account.how_heard = kwargs.get('heard_from')
        account.site = site
        account.number = account_number
        account.referrer_code = new_referrer_code()
        account.status = Account.ACTIVE
        if kwargs.get('referrer', None):
            account.referrer = kwargs['referrer']
        account.price_override = kwargs.get('price_override', None)
        account.save()
        AccountUser.objects.create(
            account=account,
            user=owner,
            number=user_number,
            username=kwargs['username']
        )
        account.subscriptions.create(plan=kwargs['plan'])
        from accounts.signals import account_created
        account_created.send(sender=account)
        return account